package edu.hawaii.ics414.blackjack.player;

import edu.hawaii.ics414.blackjack.card.Card;
import edu.hawaii.ics414.blackjack.card.GameDeck;

/**
 * The less skilled of the two card counting AIs.
 * Counts only cards of value 10.
 * 
 * @author Branden Ogata
 *
 */

public class SemiProPlayer extends ExperiencedPlayer implements CardCounter
{
  /**
   * The number of cards of value 10 that have been seen.
   * 
   */
  private int valueTenRemaining;
  
  /**
   * The total number of cards left in the deck.
   * 
   */
  private int cardsRemaining;
  
  /**
   * The number of decks in play.
   * 
   */
  private int decks;
  
  /**
   * Creates a new SemiProPlayer.
   * 
   * @param money The int equal to the starting amount of money for the new SemiProPlayer.
   * @param cards The int equal to the number of cards in the deck.
   * 
   */
  
  public SemiProPlayer(int money, int decks)
  {
    super(money);
    this.decks = decks;
    this.cardsRemaining = decks * 52;
    this.valueTenRemaining = decks * 16;
  }

  /**
   * Returns the move of this SemiProPlayer.
   * 
   * @param deck The GameDeck containing the cards to use.
   * @param hand The int indicating the hand to play on.
   * @param hole The Card that the dealer has showing.
   * 
   * @return action The Action that this SemiProPlayer intends to play.
   * 
   */
  
  @Override
  public Action getMove(GameDeck deck, int hand, Card hole)
  {
    Action action = super.getMove(deck, hand, hole);
    
    // The probability of drawing a ten-value card, then consecutive ten-value cards
    double probability = valueTenRemaining / cardsRemaining;
    double probabilityAfterOne = (valueTenRemaining - 1) / (cardsRemaining - 1);
    double probabilityAfterTwo = (valueTenRemaining - 2) / (cardsRemaining - 2);
    
    // The number for SemiPRO and dealer to reach 21
    int ownDifference = 21 - this.sum(hand);
    int dealerDifference = 21 - hole.getValue();

    // If a ten-value card would make SemiPRO bust
    if (((ownDifference < 10) && !this.isHandSoft(hand)) && (action != Action.SPLIT))
    {
      // If probability of bust is less than 0.15, then hit
      if ((this.canHit(hand)) && (probability < 0.15))
      {
        action = Action.HIT;
      }
      
      // Else if the dealer is likely to bust, then stand
      else if ((11 < dealerDifference) && (dealerDifference < 17) && (probabilityAfterOne > 0.30))
      {
        action = Action.STAND;
      }
    }
    // Else if no risk of bust and dealer is likely to bust, then hit
    else if ((this.canHit(hand)) && ((ownDifference >= 10) && (probabilityAfterTwo > 0.30) && 
             (11 < dealerDifference) && (dealerDifference < 17)))
    {
      action = Action.HIT;
    }
        
    return action;
  }

  /**
   * Updates the count of cards with value 10.
   * 
   * @param card The Card that this SemiProPlayer saw.
   * 
   */
  
  @Override
  public void updateCount(Card card)
  {
    // If the card has a value of ten, then decrement the count
    if (card.getValue() == 10)
    {
      this.valueTenRemaining--;
    }
    
    this.cardsRemaining--;
  }

  /**
   * Resets the number of cards counted.
   * 
   */

  @Override
  public void resetCount()
  {
    this.valueTenRemaining = this.decks * 16;
    this.cardsRemaining = this.decks * 52;
  }
  
  /**
   * Starts a new hand with an initial bet based on the last round.
   * 
   * @param deck The GameDeck to take cards from.
   * 
   */
  
  @Override
  public void startHand(GameDeck deck)
  {
    // If won or tied the last round, then increase the bet
    if ((this.lastRound >= 0) && 
        ((this.lastBet[0] + (this.valueTenRemaining / this.cardsRemaining)) <= 100))
    {
      this.setBet(0, this.lastBet[0] + (this.valueTenRemaining / this.cardsRemaining));
    }
    
    // Else if lost the last round, then decrease the bet
    else if ((this.lastRound < 0) && 
             ((this.lastBet[0] - (this.valueTenRemaining / this.cardsRemaining)) > 0))
    {
      this.setBet(0, this.lastBet[0] - (this.valueTenRemaining / this.cardsRemaining));
    }
    
    // Else it was a draw, so use the same bet as before
    else
    {
      this.setBet(0, this.lastBet[0]);
    }

    super.startHand(deck);
  }  

  /**
   * Returns a pointer to this SemiProPlayer as a CardCounter.
   * 
   * @return The CardCounter instance pointing to this SemiProPlayer.
   *  
   */
  
  @Override
  public CardCounter getCardCounter()
  {
    return (CardCounter) this;
  }
}
